/**********************************************
 * 
 * File Name				:	BusibuildingExceptionMappingInterceptor.java
 * 
 * Last Changed Date		: 	$Date: 2009-08-01 11:12:53 +0800 (星期六, 01 八月 2009) $
 * 
 * Last Changed Revision	:	$Revision: 86 $
 * 
 * Last Changed Author		:	$Author: cfanboy $
 * 
 * File Header URL			:	$HeadURL: svn://www.svnhost.cn/Busi-Building/code/branch/src/com/busibuilding/common/interceptor/BusibuildingExceptionMappingInterceptor.java $
 * 
 * ********************************************
 */

package com.busibuilding.common.interceptor;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.LogFactory;
import org.springframework.mail.MailAuthenticationException;
import org.springframework.mail.MailException;
import org.springframework.mail.MailParseException;
import org.springframework.mail.MailPreparationException;
import org.springframework.mail.MailSendException;

import com.busibuilding.common.Constants;
import com.busibuilding.common.action.CommonActionImpl;
import com.busibuilding.common.exceptions.ServiceException;
import com.busibuilding.common.resources.ResourceErrorMessageUtil;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig;
import com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor;

/**
 * Class Name: BusibuildingExceptionMappingInterceptor.java 
 * Description: This interceptor will be caught the exception thrown by action layer
 * 
 * @author: YU Zhipeng
 * @version: 1.0
 * @since: 1.0 Date: 2009-07-10
 */

public class BusibuildingExceptionMappingInterceptor extends
		ExceptionMappingInterceptor implements Constants {

	private static final long serialVersionUID = 1L;

	/**
	 * Interceptor init
	 */
	public void init() {
		this.setLogEnabled(true);
		this.setLogLevel("ERROR");
	}

	/**
	 * Intercept the exception and handler it.
	 * 
	 * @param invocation
	 * @return String
	 * @throws Exception
	 */
	public String intercept(ActionInvocation invocation) throws Exception {
		String result = "";

		try {
			result = invocation.invoke();
		} catch (Exception ex) {
			if (invocation.getAction() instanceof CommonActionImpl) {
				CommonActionImpl sba = (CommonActionImpl) invocation
						.getAction();
				if (ex instanceof ServiceException) {
					handleLogging(ex, ((ServiceException) ex).getErrorCode(),
							((ServiceException) ex).getErrorMessage());
					sba.addActionError(sba.getText(EXCEPTION_MESSAGE_PREFIX
							+ ((ServiceException) ex).getErrorCode()));
					result = Action.ERROR;
				} else if (ex instanceof NullPointerException) {
					result = handlerException(invocation, result, ex, sba,
							COMMON_ERROR_CODE_NULLPOINTER_EXCEPTION);
				} else if (ex instanceof ClassCastException) {
					result = handlerException(invocation, result, ex, sba,
							COMMON_ERROR_CODE_CLASSCAST_EXCEPTION);
				} else if (ex instanceof IOException) {
					result = handlerException(invocation, result, ex, sba,
							COMMON_ERROR_CODE_IO_EXCEPTION);
				} else if (ex instanceof MailAuthenticationException) {
					result = handlerException(invocation, result, ex, sba,
							COMMON_ERROR_CODE_MAIL_AUTHENTICATION_EXCEPTION);
				} else if (ex instanceof MailParseException) {
					result = handlerException(invocation, result, ex, sba,
							COMMON_ERROR_CODE_MAIL_PARSE_EXCEPTION);
				} else if (ex instanceof MailSendException) {
					result = handlerException(invocation, result, ex, sba,
							COMMON_ERROR_CODE_MAIL_SEND_EXCEPTION);
				} else if (ex instanceof MailPreparationException) {
					result = handlerException(invocation, result, ex, sba,
							COMMON_ERROR_CODE_MAIL_PREPARATION_EXCEPTION);
				} else if (ex instanceof MailException) {
					result = handlerException(invocation, result, ex, sba,
							COMMON_ERROR_CODE_MAIL_OTHERS_EXCEPTION);
				} else if (ex.getCause() instanceof SQLException){
					result = handlerException(invocation, result, ex, sba, 
							COMMON_ERROR_CODE_SQL_EXCEPTION);
				}else{
					result = handlerException(invocation, result, ex, sba,
							COMMON_ERROR_CODE_UNKNOWN);
				}
			}

		}
		return result;
	}

	/**
	 * Handler exception, put the error messages.
	 * 
	 * @param invocation
	 * @param result
	 * @param ex
	 * @param sba
	 * @param errorCode
	 * @return
	 * @throws Exception
	 */
	private String handlerException(ActionInvocation invocation, String result,
			Exception ex, CommonActionImpl sba, String errorCode)
			throws Exception {

		sba.addActionError(sba.getText(EXCEPTION_MESSAGE_PREFIX + errorCode));
		handleLogging(ex, errorCode, ResourceErrorMessageUtil
				.getStringValue(errorCode));
		List<ExceptionMappingConfig> exceptionMappings = invocation.getProxy()
				.getConfig().getExceptionMappings();
		String mappedResult = findResultFromExceptions(exceptionMappings, ex);
		if (mappedResult != null) {
			result = mappedResult;
		} else {
			throw ex;
		}
		return result;
	}

	/**
	 * Get the action result
	 * 
	 * @param exceptionMappings
	 * @param t
	 * @return
	 */
	private String findResultFromExceptions(
			List<ExceptionMappingConfig> exceptionMappings, Throwable t) {

		String result = null;
		if (exceptionMappings != null) {
			int deepest = Integer.MAX_VALUE;
			for (Iterator<ExceptionMappingConfig> iter = exceptionMappings
					.iterator(); iter.hasNext();) {
				ExceptionMappingConfig exceptionMappingConfig = iter.next();
				int depth = getDepth(exceptionMappingConfig
						.getExceptionClassName(), t);
				if (depth >= 0 && depth < deepest) {
					deepest = depth;
					result = exceptionMappingConfig.getResult();
				}
			}
		}

		return result;

	}

	/**
	 * Logger the exceptions
	 * 
	 * @param e
	 * @param errorCode
	 * @param errorMsg
	 */
	private void handleLogging(Exception e, String errorCode, String errorMsg) {
		if (logCategory != null) {
			if (categoryLogger == null) {
				categoryLogger = LogFactory.getLog(logCategory);
			}

			categoryLogger
					.error(" Please contact you administrator immediately.  The reason of system error see below. \n Error Code :"
							+ errorCode + "\n Error Messages: " + errorMsg);

			doLog(categoryLogger, e);
		} else {
			log
					.error(" Please contact you administrator immediately.  The reason of system error see below. \n Error Code :"
							+ errorCode + "\n Error Messages: " + errorMsg);
			doLog(log, e);
		}
	}
}